package com.demo2do.fms.admin.dao.business;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.GenericJdbcSupport;
import com.demo2do.core.utils.CollectionUtils;
import com.demo2do.fms.admin.entity.export.business.ExpenseSheetFooter;
import com.demo2do.fms.admin.entity.export.business.ExpenseSheetHeader;
import com.demo2do.fms.admin.entity.export.business.ExpenseSheetItem;
import com.demo2do.fms.admin.utils.AmountUtils;
import com.demo2do.fms.entity.authority.Organization;
import com.demo2do.fms.entity.business.balance.OtherFee;
import com.demo2do.fms.entity.business.shipment.DispatchOrder;
import com.demo2do.fms.entity.business.shipment.TransportCost;
import com.demo2do.fms.entity.data.business.LoadPlace;
import com.demo2do.fms.entity.data.business.OtherFeeType;
import com.demo2do.fms.entity.driver.Employee;
import com.demo2do.fms.entity.vehicle.source.Vehicle;

/**
 *
 * @author Ark
 *
 */
@Repository("expenseSheetDaoSupport")
public class ExpenseSheetDaoSupport {
    
    private static final Long ANJIE_ID = 1001L;

    /**
     * 射阳分公司
     */
    private static final Long ANJIE_ID_2 = 3230L;
    
    @Autowired
    private OtherFeeDaoSupport otherFeeDaoSupport;
    
    @Autowired
    private SequenceDaoSupport sequenceDaoSupport;
    
    @Autowired
    private GenericDaoSupport genericDaoSupport;
    
    @Autowired
    private GenericJdbcSupport genericJdbcSupport;
    
    /**
     * 构造报销单头部
     * 
     * @param dispatchOrder
     * @param transportCost
     * @return
     */
    public ExpenseSheetHeader prepareExpenseSheetHeader(DispatchOrder dispatchOrder, TransportCost transportCost) {
        
        Organization organization = genericDaoSupport.load(Organization.class, dispatchOrder.getOrganizationId());  // 公司
        
        Vehicle vehicle = genericDaoSupport.load(Vehicle.class, dispatchOrder.getVehicleId());  // 板车

        // 驾驶员
        Employee mainDriver = genericDaoSupport.load(Employee.class, dispatchOrder.getMainDriverId());  // 主驾
        Employee firstViceDriver = null;   // 第一副驾
        if(dispatchOrder.getFirstViceDriverId() != null && dispatchOrder.getFirstViceDriverId() != 0) {
            firstViceDriver = genericDaoSupport.load(Employee.class, dispatchOrder.getFirstViceDriverId());
        }
        
        // sequence
        String senquenceCode = sequenceDaoSupport.getSequence(organization.getCode(), "REIMBURSED_CODE");
        
        // 公司名称
        String organizationName = "上海" + organization.getName() + "轿车运输有限公司";
        
        return new ExpenseSheetHeader(organizationName, senquenceCode, vehicle, transportCost, mainDriver, firstViceDriver);
        
    }
    
    /**
     * 构造报销单每页  派车单信息集合
     * 
     * @param dispatchOrders
     * @param transportCosts
     * @param itemAmount
     * @return
     */
    public List<ExpenseSheetItem> prepareExpenseSheetItem(List<DispatchOrder> dispatchOrders, Map<String, TransportCost> transportCosts, int itemAmount) {
        
        List<ExpenseSheetItem> items = new ArrayList<ExpenseSheetItem>();
        
        for(int i=0; i<dispatchOrders.size(); i++) {
            ExpenseSheetItem item = this.prepareExpenseSheetItem(itemAmount + i+1, dispatchOrders.get(i), transportCosts.get(dispatchOrders.get(i).getId().toString()));
            items.add(item);
        }
        
        return items;
        
    }
    
    /**
     * 构造每条派车单信息
     * 
     * @param num
     * @param dispatchOrder
     * @param transportCost
     * @return
     */
    private ExpenseSheetItem prepareExpenseSheetItem(int num, DispatchOrder dispatchOrder, TransportCost transportCost) {
        
        // prepare create data
        LoadPlace startAddr = genericDaoSupport.load(LoadPlace.class, dispatchOrder.getStartFacilityId());
        LoadPlace endAddr = genericDaoSupport.load(LoadPlace.class, dispatchOrder.getDestinationFacilityId());
        
        Map<String, Object> carSumResult = genericJdbcSupport.queryForObject("SELECT FC_GET_CARSUMMARY(:dispatchOrderId) AS CARSUMMARY FROM DUAL", "dispatchOrderId", dispatchOrder.getId());
        String carSum = (String) carSumResult.get("CARSUMMARY");
        
        Map<String, Object> otherFeeResult = genericJdbcSupport.queryForObject("SELECT FC_GET_OTHER_FEE(:dispatchOrderId) AS fee FROM DUAL", "dispatchOrderId", dispatchOrder.getId());
        BigDecimal otherFee = ((BigDecimal) otherFeeResult.get("fee") == null) ? BigDecimal.ZERO : ((BigDecimal) otherFeeResult.get("fee"));
        
        return new ExpenseSheetItem(num, dispatchOrder, transportCost, startAddr, endAddr, carSum, otherFee);
        
    }
    
    /**
     * 构造其他费用详情
     * 
     * @param dispatchOrders
     * @return
     */
    public String prepareOtherFeeDetail(List<DispatchOrder> dispatchOrders) {
        
        String result = "";
        
        int i = 1;
        
        for (DispatchOrder dispatchOrder : dispatchOrders) {
            
            // 1.get not anji's otherFee and anji's otherFee by dispatchOrderId
            List<OtherFee> otherFees = otherFeeDaoSupport.list(false, dispatchOrder.getId());
            List<OtherFee> anjiOtherFees = otherFeeDaoSupport.list(true, dispatchOrder.getId());
            Map<String, OtherFee> anjiFees = CollectionUtils.constructMapValue(anjiOtherFees, "otherFeeTypeId");
            int k = 0;
            
            if(!otherFees.isEmpty()) {
                
                for(OtherFee otherFee : otherFees) {
                    OtherFee fee = otherFee;
                    
                    // 2.get otherFeeType by otherFee's otherFeeTypeId
                    OtherFeeType otherFeeType = genericDaoSupport.load(OtherFeeType.class, otherFee.getOtherFeeTypeId());
                    
                    // if anji's is not empty and otherFee > 0.0001 then otherFee = anjiOtherFee
                    if(!MapUtils.isEmpty(anjiFees)) {
                        OtherFee anjiFee = anjiFees.get(otherFee.getOtherFeeTypeId().toString());
                        if(anjiFee != null && anjiFee.getOtherFee().compareTo(new BigDecimal("0.0001")) > 0) {
                            fee = anjiFee;
                        }
                    }
                    
                    // if otherFee > 0.0001 then generate result
                    if(fee.getOtherFee().compareTo(new BigDecimal(0.0001)) > 0) {
                        if(k == 0) {
                            result = result + "(" + i + ")";
                        }
                        result = result + otherFeeType.getName() + ":" + fee.getOtherFee() + ";";
                        k++;
                    }
                }
            }
            
            i++;
        }
        
        return result;
    }
    
    /**
     * 构造派车单尾部信息
     * 
     * @param dispatchOrders
     * @param costs
     * @param items
     * @return
     */
    public ExpenseSheetFooter prepareExpenseSheetFooter(List<DispatchOrder> dispatchOrders, Map<String, TransportCost> costs, List<ExpenseSheetItem> items) {
        
        int carNum = 0;
        boolean isAnjie = dispatchOrders.get(0).getOrganizationId().equals(ANJIE_ID) || dispatchOrders.get(0).getOrganizationId().equals(ANJIE_ID_2);
        BigDecimal driverSalary = BigDecimal.ZERO,
                   internalOilFeeCompensation = BigDecimal.ZERO,
                   internalOilUsageCompen = BigDecimal.ZERO,
                   oilYield = BigDecimal.ZERO,
                   oilUsage = isAnjie ? BigDecimal.ZERO : null;
                   
        // 司机工资、内部油贴现等
        for(DispatchOrder dispatchOrder : dispatchOrders) {
            
            // 1.calculate driverSalary
            driverSalary = driverSalary.add(costs.get(dispatchOrder.getId().toString()).getMainDriverSalary())
                                       .add(costs.get(dispatchOrder.getId().toString()).getFirstViceDriverSalary());
            
            // 2.calculate internalOilFeeCompensation
            internalOilFeeCompensation = internalOilFeeCompensation.add(costs.get(dispatchOrder.getId().toString()).getInternalOilFeeCompensation());
            
            // 3.calculate internalOilUsageCompen
            internalOilUsageCompen = internalOilUsageCompen.add(costs.get(dispatchOrder.getId().toString()).getInternalOilUsageCompen());
            
            // 4.calculate oilYield
            oilYield = oilYield.add(costs.get(dispatchOrder.getId().toString()).getInternalOilUsage())
                               .subtract(costs.get(dispatchOrder.getId().toString()).getInternalOilUsageCompen());
            
            // 5.if this company is anjie calculate oilUsage
            if(isAnjie) {
                oilUsage = oilUsage.add(costs.get(dispatchOrder.getId().toString()).getOilUsage());
            }
            
            // 6. calculate carSum
            carNum = carNum + (dispatchOrder.getActualLoadNumber() == null ? 0 : dispatchOrder.getActualLoadNumber());
        }
        
        BigDecimal fullLoadDistance = BigDecimal.ZERO,
                   emptyLoadDistance = BigDecimal.ZERO,
                   roadFee = BigDecimal.ZERO,
                   totalOilFeeReimbursed = BigDecimal.ZERO,
                   otherFee = BigDecimal.ZERO;
        
        // 运输成本小计信息
        for(ExpenseSheetItem item : items) {
            fullLoadDistance = fullLoadDistance.add(item.getFullLoadDistance());
            emptyLoadDistance = emptyLoadDistance.add(item.getEmptyLoadDistance());
            roadFee = roadFee.add(item.getRoadFee());
            totalOilFeeReimbursed = totalOilFeeReimbursed.add(item.getTotalOilFeeReimbursed());
            otherFee = otherFee.add(item.getOtherFee());
        }
        
        // 计算总计并转换成中文大写
        BigDecimal result = roadFee.add(totalOilFeeReimbursed).add(otherFee);
        String total = AmountUtils.number2CNMontrayUnit(result);
        
        return new ExpenseSheetFooter(carNum, driverSalary, internalOilFeeCompensation, internalOilUsageCompen, oilUsage, oilYield, fullLoadDistance, emptyLoadDistance, roadFee, totalOilFeeReimbursed, otherFee, total);
        
    }

}
